﻿(*                  FnSharp              

   Base class library extensions and frameworks aimed 
   specifically at improving F# developers lives!

   Written by: Huw Simpson
   License: Microsoft Public License (Ms-PL) 
   Available at: http://fnsharp.codeplex.com

*)
namespace FnSharp.Bcl.Core

    open System
    open System.Threading

    /// Mutable atom cell.
    type Atom<'T when 'T : not struct>(value : 'T) = //Adapted from http://fssnip.net/2r, ms-pl license (Nick Palladinos)
        let refCell = ref value
    
        let rec switch f = 
            let currentValue = !refCell
            let result = Interlocked.CompareExchange<'T>(refCell, f currentValue, currentValue)
            if obj.ReferenceEquals(result, currentValue) then ()
            else Thread.SpinWait 20; switch f
        
        /// Return the currently referenced type.
        member self.Value with get() : 'T = !refCell

        /// Switch references atomically.
        member self.Switch (f : 'T -> 'T) : unit = switch f

    [<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
    module Atom =
        /// Create a new mutable atom cell
        let atom value = new Atom<_>(value)
        
        let (!) (atom : Atom<_>) = atom.Value
    
        /// Switch references atomically.
        let switch (atom : Atom<_>) (f : _ -> _) = atom.Switch f

        let (|AtomCell|) (atomCell : Atom<'T>) = !atomCell
        